/**     
 * @{#} SocketWrap.java Create on 2011-7-22 上午09:49:32     
 *     
 * Copyright (c) 2011 by xiaofeng.zhouxf     
 */
package com.sefer.memcached.connect;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

import com.sefer.memcached.constants.ErrorCode;
import com.sefer.memcached.exception.ClientException;

/**
 * Wrap Socket for add server information.
 * 
 * @author <a href="mailto:xiaofeng.zhouxf83@gmail.com">xiaofeng.zhouxf</a>
 * @version 1.0
 */
public class SocketWrap {

	private Socket socket;

	private Server server;

	SocketWrap(Socket socket, Server server) {
		super();
		this.socket = socket;
		this.server = server;
	}

	public SocketWrap(Server server) {
		super();
		this.server = server;
	}

	public Socket getSocket() {
		return socket;
	}

	public void setSocket(Socket socket) {
		this.socket = socket;
	}

	public Server getServer() {
		return server;
	}

	public void setServer(Server server) {
		this.server = server;
	}

	public void write(byte[] bytes) {
		try {
			socket.getOutputStream().write(bytes);
		} catch (IOException e) {
			throw new ClientException(ErrorCode.E_500, e, e.getMessage());
		}
	}

	public void flush() {
		try {
			socket.getOutputStream().flush();
		} catch (IOException e) {
			throw new ClientException(ErrorCode.E_500, e, e.getMessage());
		}
	}

	public String read() throws IOException {
		StringBuilder sb = new StringBuilder();
		byte[] b = new byte[1];
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		boolean eol = false;
		DataInputStream in;
		in = new DataInputStream(new BufferedInputStream(
				socket.getInputStream()));
		while (in.read(b, 0, 1) != -1) {
			// 10: lf , 13: cr
			if (b[0] == 13) {
				eol = true;
			} else {
				if (eol) {
					if (b[0] == 10)
						break;

					eol = false;
				}
			}
			bos.write(b, 0, 1);
		}

		if (bos == null || bos.size() <= 0) {
			throw new IOException(
					"++++ Stream appears to be dead, so closing it down");
		}

		sb.append(bos.toString().trim());

		// if result is begin with VALUE, is should read until 'END'
		if (bos.toString().trim().startsWith("VALUE")) {
			sb.delete(0, sb.length());
			while (true) {
				bos.reset();
				while (in.read(b, 0, 1) != -1) {
					// 10: lf , 13: cr
					if (b[0] == 13) {
						eol = true;
					} else {
						if (eol) {
							if (b[0] == 10)
								break;

							eol = false;
						}
					}
					bos.write(b, 0, 1);
				}
				if (bos.toString().trim().equals("END")) {
					break;
				}
				sb.append(bos.toString().trim());
				sb.append("\r\n");
			}
		}
		return sb.toString();
	}

	public void close() {
		try {
			socket.close();
		} catch (IOException e1) {
			throw new ClientException(ErrorCode.E_302, "close socket error");
		}
	}
}
